home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / hashsig / hashsig.lha / h.c < prev    next >
C/C++ Source or Header  |  1993-08-09  |  23KB  |  806 lines

  1. /*
  2.  * This file contains some of the hash methods and hash-function
  3.  * specific information.  At the present time, it includes a
  4.  * very slow and inefficient implementation of Snefru.  It calls
  5.  * MD4, the implementation of which is included in another file.
  6.  * Further hash functions can be added in the future as warranted.
  7.  * Please contact Ralph C. Merkle before doing so to insure that the
  8.  * constant value assigned to the new hash method is unique and does
  9.  * not collide with other values.  In any event, values below 100
  10.  * are reserved for use by Xerox.
  11.  */
  12. /*
  13.   Copyright (c) Xerox Corporation 1990.  All rights reserved.
  14.   
  15.   The following notices apply to the implementation of Snefru and
  16.   related software contained in this file.  They do not apply
  17.   to the other files included with this software, which include
  18.   implementations of MD4 and of the Abstract Xerox Hash Signature.
  19.   Please refer to the appropriate notices.
  20.  
  21.   License to copy and use this software (an implementation of Snefru)
  22.   is granted provided that it is identified as the "Xerox Secure Hash
  23.   Function" in all material mentioning or referencing this software
  24.   or this hash function.
  25.   
  26.   License is also granted to make and use derivative works provided that such
  27.   works are identified as "derived from the Xerox Secure Hash Function" in
  28.   all material mentioning or referencing the derived work.
  29.  
  30.   XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
  31.   MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
  32.   ANY PARTICULAR PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
  33.   WARRANTY OF ANY KIND.
  34.   
  35.   These notices must be retained in any copies of any part of this software.
  36.   
  37.   Updated information about Snefru is available from arisia.xerox.com in
  38.   directory /pub/hash by anonymous FTP.  The README file provides a quick
  39.   introduction to the subdirectories.
  40. */
  41. #include <stdio.h>
  42. #define MAX_INPUT_BLOCK_SIZE 16
  43. #define SNEFRU_INPUT_BLOCK_SIZE 16
  44. #define OUTPUT_BLOCK_SIZE 8
  45. #define MAX_SBOX_COUNT 8
  46. #define MD4_METHOD 100
  47. #define SNEFRU3_METHOD 3
  48. #define SNEFRU4_METHOD 4
  49. #define SNEFRU512_INPUT_BLOCK_SIZE 16
  50. #define SNEFRU384_INPUT_BLOCK_SIZE 12
  51. #define SNEFRU256_INPUT_BLOCK_SIZE 8
  52. #define SNEFRU128_INPUT_BLOCK_SIZE 4
  53. #define DEBUG_SNEFRU 0
  54.  
  55. #define round512(L,C,N,SB)    SBE=SB[C&0xffL];L^=SBE;N^=SBE
  56. #define rotate512(B)    B=(B>>shift) | (B<<leftShift)
  57.  
  58. extern void ErrAbort();
  59. extern void Copy();
  60. extern void Md4Block();
  61. extern void PrintIt();
  62. extern void Increment64BitCounter();
  63.  
  64. typedef unsigned long int word32;
  65. int     shiftTable[4] = {16, 8, 16, 24};
  66.  
  67. /* The standard S boxes must be defined in another file */
  68. extern word32 standardSBoxes[MAX_SBOX_COUNT][256];
  69.  
  70. void    SnefruBlock (output, outputBlockSize,
  71.         input, inputBlockSize, securityLevel)
  72.     word32 output[/* outputBlockSize */];
  73.     int outputBlockSize;
  74.     word32 input[/* inputBlockSize */];
  75.     int     inputBlockSize;
  76.     int     securityLevel;
  77. {
  78.  
  79.     /* holds the array of data being hashed  */
  80.     word32 block[MAX_INPUT_BLOCK_SIZE];
  81.     word32 SBoxEntry;    /* just a temporary */
  82.     int     shift;
  83.     int     i;
  84.     int     index;
  85.     int     next, last;
  86.     int     byteInWord;
  87.  
  88.     /* Test for various error conditions and logic problems  */
  89.     if (securityLevel * 2 > MAX_SBOX_COUNT)
  90.         ErrAbort ("Too few S-boxes");
  91.     if (outputBlockSize < 2)
  92.         ErrAbort (" outputBlockSize too small");
  93.     if ( outputBlockSize > inputBlockSize)
  94.         ErrAbort ("logic error, outputBlockSize is too big");
  95.  
  96.     /* initialize the block to be hashed from the input  */
  97.     Copy(block, input, inputBlockSize);
  98.     /*  increase block size till it's a multiple of 4 words
  99.         and pad the new words with 0's */
  100.     while ( (inputBlockSize & 3) != 0 )
  101.         block[inputBlockSize++] = 0L;
  102.  
  103.     /*  complete error testing with updated inputBlockSize  */
  104.     if ( (outputBlockSize+2) > inputBlockSize)
  105.         ErrAbort ("logic error, inputBlockSize is too small");
  106.     if (inputBlockSize > MAX_INPUT_BLOCK_SIZE)
  107.         ErrAbort ("Logic error, inputBlockSize > MAX_INPUT_BLOCK_SIZE");
  108.     /* All the error conditions have now been checked -- everything should
  109.        work smoothly  */
  110.     /* Note that we are computing securityLevel * inputBlockSize * 4
  111.        rounds.  */
  112.     for (index = 0; index < securityLevel; index++) {
  113.  
  114.  
  115.         for (byteInWord = 0; byteInWord < 4; byteInWord++) {
  116.  
  117.  
  118.             for (i = 0; i < inputBlockSize; i++) {
  119.                 
  120.                 next = (i + 1) % inputBlockSize;
  121.                 /*  last = (i-1) MOD inputBlockSize */
  122.                 last = (i + inputBlockSize - 1) %
  123.                     inputBlockSize;
  124.  
  125.  
  126.                 SBoxEntry = standardSBoxes
  127.                     [2 * index + ((i / 2) & 1)]
  128.                     [block[i] & 0xff];
  129.                 block[next] ^= SBoxEntry;
  130.                 block[last] ^= SBoxEntry;
  131.             };
  132.  
  133.  
  134.             /* Rotate right all 32-bit words in the entire block
  135.                at once.  */
  136.             shift = shiftTable[byteInWord];
  137.             for (i = 0; i < inputBlockSize; i++)
  138.                 block[i] =    (block[i] >> shift) |
  139.                         (block[i] << (32 - shift));
  140.  
  141.  
  142.         };        /* end of byteInWord going from 0 to 3 */
  143.  
  144.  
  145.     };            /* end of index going from 0 to
  146.                    securityLevel-1 */
  147.  
  148.  
  149.  
  150.     for (i = 0; i < outputBlockSize; i++)
  151.         output[i] = input[i] ^ block[inputBlockSize - 1 - i];
  152.  
  153.  
  154. }
  155.  
  156.  
  157. /*
  158.  * Snefru512 is a more efficient and specialized version of SnefruBlock.
  159.  * It accepts an input of 16 32-bit words and produces an output of
  160.  * 32-bit words.  The output size cannot be bigger than 14 32-bit words,
  161.  * or a serious degradation in security will occur.
  162.  */
  163. void
  164. Snefru512 (output, outputBlockSize, input, inputBlockSize, securityLevel)
  165.     word32    output[];
  166.     int    outputBlockSize;
  167.     word32    input[SNEFRU512_INPUT_BLOCK_SIZE];
  168.     int    inputBlockSize;
  169.     int    securityLevel;
  170. {
  171.     static int shiftTable[4] = {16, 8, 16, 24};
  172.     /* the array of data being hashed  */
  173.     word32    SBE;    /* just a temporary */
  174.     int     shift, leftShift;
  175.     int     index;
  176.     int     byteInWord;
  177.     word32    *SBox0;
  178.     word32    *SBox1;
  179.     word32    B00,B01,B02,B03,B04,B05,B06,B07,B08,B09,B10,B11,B12,B13,B14,B15;
  180.  
  181.     /* initialize the block to be hashed from the input  */
  182.     B00 = input[0];
  183.     B01 = input[1];
  184.     B02 = input[2];
  185.     B03 = input[3];
  186.     B04 = input[4];
  187.     B05 = input[5];
  188.     B06 = input[6];
  189.     B07 = input[7];
  190.     B08 = input[8];
  191.     B09 = input[9];
  192.     B10 = input[10];
  193.     B11 = input[11];
  194.     B12 = 0;
  195.     B13 = 0;
  196.     B14 = 0;
  197.     B15 = 0;
  198.     switch (inputBlockSize) {
  199.     case 16:    B15 = input[15];
  200.     case 15:    B14 = input[14];
  201.     case 14:    B13 = input[13];
  202.     case 13:    B12 = input[12];
  203.         break;
  204.     default:    ErrAbort("bad input size to snefru512");
  205.     };
  206.  
  207.     for (index = 0; index < securityLevel; index++) {
  208.         SBox0 = standardSBoxes[2*index+0];
  209.         SBox1 = standardSBoxes[2*index+1];
  210.         for (byteInWord = 0; byteInWord < 4; byteInWord++) {
  211.             round512(B15,B00,B01,SBox0);
  212.             round512(B00,B01,B02,SBox0);
  213.             round512(B01,B02,B03,SBox1);
  214.             round512(B02,B03,B04,SBox1);
  215.             round512(B03,B04,B05,SBox0);
  216.             round512(B04,B05,B06,SBox0);
  217.             round512(B05,B06,B07,SBox1);
  218.             round512(B06,B07,B08,SBox1);
  219.             round512(B07,B08,B09,SBox0);
  220.             round512(B08,B09,B10,SBox0);
  221.             round512(B09,B10,B11,SBox1);
  222.             round512(B10,B11,B12,SBox1);
  223.             round512(B11,B12,B13,SBox0);
  224.             round512(B12,B13,B14,SBox0);
  225.             round512(B13,B14,B15,SBox1);
  226.             round512(B14,B15,B00,SBox1);
  227.             /*
  228.              * Rotate right all 32-bit words in the entire block
  229.              * at once.
  230.              */
  231.             shift = shiftTable[byteInWord];
  232.             leftShift = 32-shift;
  233.             rotate512(B00);
  234.             rotate512(B01);
  235.             rotate512(B02);
  236.             rotate512(B03);
  237.             rotate512(B04);
  238.             rotate512(B05);
  239.             rotate512(B06);
  240.             rotate512(B07);
  241.             rotate512(B08);
  242.             rotate512(B09);
  243.             rotate512(B10);
  244.             rotate512(B11);
  245.             rotate512(B12);
  246.             rotate512(B13);
  247.             rotate512(B14);
  248.             rotate512(B15);
  249.         };        /* end of byteInWord going from 0 to 3 */
  250.     };            /* end of index going from 0 to
  251.                  * securityLevel-1 */
  252.  
  253.     switch (outputBlockSize) {
  254.     case 14:    output[13] = input[13] ^ B02;
  255.     case 13:    output[12] = input[12] ^ B03;
  256.     case 12:    output[11] = input[11] ^ B04;
  257.     case 11:    output[10] = input[10] ^ B05;
  258.     case 10:    output[ 9] = input[ 9] ^ B06;
  259.     case  9:    output[ 8] = input[ 8] ^ B07;
  260.     case  8:    output[ 7] = input[ 7] ^ B08;
  261.     case  7:    output[ 6] = input[ 6] ^ B09;
  262.     case  6:    output[ 5] = input[ 5] ^ B10;
  263.     case  5:    output[ 4] = input[ 4] ^ B11;
  264.     case  4:    output[ 3] = input[ 3] ^ B12;
  265.     case  3:    output[ 2] = input[ 2] ^ B13;
  266.     case  2:    output[ 1] = input[ 1] ^ B14;
  267.     case  1:    output[ 0] = input[ 0] ^ B15;
  268.             break;
  269.     default: ErrAbort("Bad output block size");
  270.     };
  271. };
  272.  
  273. /*
  274.  * Snefru384 is a more efficient and specialized version of SnefruBlock.
  275.  * It accepts an input of 12 32-bit words and produces an output of
  276.  * outputBlockSize 32-bit words.  The output size cannot be bigger
  277.  * than 10 32-bit words, or a serious degradation in security will occur.
  278.  */
  279. void
  280. Snefru384 (output, outputBlockSize, input, inputBlockSize, securityLevel)
  281.     word32    output[];
  282.     int    outputBlockSize;
  283.     word32    input[SNEFRU384_INPUT_BLOCK_SIZE];
  284.     int    inputBlockSize;
  285.     int    securityLevel;
  286. {
  287.     static int shiftTable[4] = {16, 8, 16, 24};
  288.     /* the array of data being hashed  */
  289.     word32    SBE;    /* just a temporary */
  290.     int     shift, leftShift;
  291.     int     index;
  292.     int     byteInWord;
  293.     word32    *SBox0;
  294.     word32    *SBox1;
  295.     word32    B00,B01,B02,B03,B04,B05,B06,B07,B08,B09,B10,B11;
  296.  
  297.     /* initialize the block to be hashed from the input  */
  298.     B00 = input[0];
  299.     B01 = input[1];
  300.     B02 = input[2];
  301.     B03 = input[3];
  302.     B04 = input[4];
  303.     B05 = input[5];
  304.     B06 = input[6];
  305.     B07 = input[7];
  306.     B08 = 0;
  307.     B09 = 0;
  308.     B10 = 0;
  309.     B11 = 0;
  310.     switch (inputBlockSize) {
  311.     case 12:    B11 = input[11];
  312.     case 11:    B10 = input[10];
  313.     case 10:    B09 = input[9];
  314.     case  9:    B08 = input[8];
  315.         break;
  316.     default:    ErrAbort("bad input size to snefru384");
  317.     };
  318.  
  319.  
  320.  
  321.     for (index = 0; index < securityLevel; index++) {
  322.         SBox0 = standardSBoxes[2*index+0];
  323.         SBox1 = standardSBoxes[2*index+1];
  324.         for (byteInWord = 0; byteInWord < 4; byteInWord++) {
  325.             round512(B11,B00,B01,SBox0);
  326.             round512(B00,B01,B02,SBox0);
  327.             round512(B01,B02,B03,SBox1);
  328.             round512(B02,B03,B04,SBox1);
  329.             round512(B03,B04,B05,SBox0);
  330.             round512(B04,B05,B06,SBox0);
  331.             round512(B05,B06,B07,SBox1);
  332.             round512(B06,B07,B08,SBox1);
  333.             round512(B07,B08,B09,SBox0);
  334.             round512(B08,B09,B10,SBox0);
  335.             round512(B09,B10,B11,SBox1);
  336.             round512(B10,B11,B00,SBox1);
  337.             /*
  338.              * Rotate right all 32-bit words in the entire block
  339.              * at once.
  340.              */
  341.             shift = shiftTable[byteInWord];
  342.             leftShift = 32-shift;
  343.             rotate512(B00);
  344.             rotate512(B01);
  345.             rotate512(B02);
  346.             rotate512(B03);
  347.             rotate512(B04);
  348.             rotate512(B05);
  349.             rotate512(B06);
  350.             rotate512(B07);
  351.             rotate512(B08);
  352.             rotate512(B09);
  353.             rotate512(B10);
  354.             rotate512(B11);
  355.         };        /* end of byteInWord going from 0 to 3 */
  356.     };            /* end of index going from 0 to
  357.                  * securityLevel-1 */
  358.  
  359.     switch (outputBlockSize) {
  360.     case 10:    output[ 9] = input[ 9] ^ B02;
  361.     case  9:    output[ 8] = input[ 8] ^ B03;
  362.     case  8:    output[ 7] = input[ 7] ^ B04;
  363.     case  7:    output[ 6] = input[ 6] ^ B05;
  364.     case  6:    output[ 5] = input[ 5] ^ B06;
  365.     case  5:    output[ 4] = input[ 4] ^ B07;
  366.     case  4:    output[ 3] = input[ 3] ^ B08;
  367.     case  3:    output[ 2] = input[ 2] ^ B09;
  368.     case  2:    output[ 1] = input[ 1] ^ B10;
  369.     case  1:    output[ 0] = input[ 0] ^ B11;
  370.             break;
  371.     default: ErrAbort("Bad output block size");
  372.     };
  373. };
  374.  
  375.  
  376. /*
  377.  * Snefru256 is a more efficient and specialized version of SnefruBlock.
  378.  * It accepts an input of 8 32-bit words and produces an output of
  379.  * outputBlockSize 32-bit words.  The output size cannot be bigger
  380.  * than 6 32-bit words, or a serious degradation in security will occur.
  381.  */
  382. void
  383. Snefru256 (output, outputBlockSize, input, inputBlockSize, securityLevel)
  384.     word32    output[];
  385.     int    outputBlockSize;
  386.     word32    input[SNEFRU256_INPUT_BLOCK_SIZE];
  387.     int    inputBlockSize;
  388.     int    securityLevel;
  389. {
  390.     static int shiftTable[4] = {16, 8, 16, 24};
  391.     /* the array of data being hashed  */
  392.     word32    SBE;    /* just a temporary */
  393.     int     shift, leftShift;
  394.     int     index;
  395.     int     byteInWord;
  396.     word32    *SBox0;
  397.     word32    *SBox1;
  398.     word32    B00,B01,B02,B03,B04,B05,B06,B07;
  399.  
  400.     /* initialize the block to be hashed from the input  */
  401.     B00 = input[0];
  402.     B01 = input[1];
  403.     B02 = input[2];
  404.     B03 = input[3];
  405.     B04 = 0;
  406.     B05 = 0;
  407.     B06 = 0;
  408.     B07 = 0;
  409.     switch (inputBlockSize) {
  410.     case 8:    B07 = input[7];
  411.     case 7:    B06 = input[6];
  412.     case 6:    B05 = input[5];
  413.     case 5:    B04 = input[4];
  414.         break;
  415.     default:    ErrAbort("bad input size to snefru256");
  416.     };
  417.  
  418.  
  419.     for (index = 0; index < securityLevel; index++) {
  420.         SBox0 = standardSBoxes[2*index+0];
  421.         SBox1 = standardSBoxes[2*index+1];
  422.         for (byteInWord = 0; byteInWord < 4; byteInWord++) {
  423.             round512(B07,B00,B01,SBox0);
  424.             round512(B00,B01,B02,SBox0);
  425.             round512(B01,B02,B03,SBox1);
  426.             round512(B02,B03,B04,SBox1);
  427.             round512(B03,B04,B05,SBox0);
  428.             round512(B04,B05,B06,SBox0);
  429.             round512(B05,B06,B07,SBox1);
  430.             round512(B06,B07,B00,SBox1);
  431.             /*
  432.              * Rotate right all 32-bit words in the entire block
  433.              * at once.
  434.              */
  435.             shift = shiftTable[byteInWord];
  436.             leftShift = 32-shift;
  437.             rotate512(B00);
  438.             rotate512(B01);
  439.             rotate512(B02);
  440.             rotate512(B03);
  441.             rotate512(B04);
  442.             rotate512(B05);
  443.             rotate512(B06);
  444.             rotate512(B07);
  445.         };        /* end of byteInWord going from 0 to 3 */
  446.     };            /* end of index going from 0 to
  447.                  * securityLevel-1 */
  448.  
  449.     switch (outputBlockSize) {
  450.     case  6:    output[ 5] = input[ 5] ^ B02;
  451.     case  5:    output[ 4] = input[ 4] ^ B03;
  452.     case  4:    output[ 3] = input[ 3] ^ B04;
  453.     case  3:    output[ 2] = input[ 2] ^ B05;
  454.     case  2:    output[ 1] = input[ 1] ^ B06;
  455.     case  1:    output[ 0] = input[ 0] ^ B07;
  456.             break;
  457.     default: ErrAbort("Bad output block size");
  458.     };
  459. };
  460.  
  461. /*
  462.  * Snefru128 is a more efficient and specialized version of SnefruBlock.
  463.  * It accepts an input of 4 32-bit words and produces an output of
  464.  * 32-bit words.  The output size cannot be bigger than 2 32-bit words,
  465.  * or a serious degradation in security will occur.
  466.  */
  467. void
  468. Snefru128 (output, outputBlockSize, input, inputBlockSize, securityLevel)
  469.     word32    output[];
  470.     int    outputBlockSize;
  471.     word32    input[SNEFRU128_INPUT_BLOCK_SIZE];
  472.     int    inputBlockSize;
  473.     int    securityLevel;
  474. {
  475.     static int shiftTable[4] = {16, 8, 16, 24};
  476.     /* the array of data being hashed  */
  477.     word32    SBE;    /* just a temporary */
  478.     int     shift, leftShift;
  479.     int     index;
  480.     int     byteInWord;
  481.     word32    *SBox0;
  482.     word32    *SBox1;
  483.     word32    B00,B01,B02,B03;
  484.  
  485.     /* initialize the block to be hashed from the input  */
  486.     B00 = 0;
  487.     B01 = 0;
  488.     B02 = 0;
  489.     B03 = 0;
  490.     switch (inputBlockSize) {
  491.     case 4:    B03 = input[3];
  492.     case 3:    B02 = input[2];
  493.     case 2:    B01 = input[1];
  494.     case 1:    B00 = input[0];
  495.         break;
  496.     default:    ErrAbort("bad input size to snefru128");
  497.     };
  498.  
  499.  
  500.     for (index = 0; index < securityLevel; index++) {
  501.         SBox0 = standardSBoxes[2*index+0];
  502.         SBox1 = standardSBoxes[2*index+1];
  503.         for (byteInWord = 0; byteInWord < 4; byteInWord++) {
  504.             round512(B03,B00,B01,SBox0);
  505.             round512(B00,B01,B02,SBox0);
  506.             round512(B01,B02,B03,SBox1);
  507.             round512(B02,B03,B00,SBox1);
  508.             /*
  509.              * Rotate right all 32-bit words in the entire block
  510.              * at once.
  511.              */
  512.             shift = shiftTable[byteInWord];
  513.             leftShift = 32-shift;
  514.             rotate512(B00);
  515.             rotate512(B01);
  516.             rotate512(B02);
  517.             rotate512(B03);
  518.         };        /* end of byteInWord going from 0 to 3 */
  519.     };            /* end of index going from 0 to
  520.                  * securityLevel-1 */
  521.  
  522.     switch (outputBlockSize) {
  523.     case  2:    output[ 1] = input[ 1] ^ B02;
  524.     case  1:    output[ 0] = input[ 0] ^ B03;
  525.             break;
  526.     default: ErrAbort("Bad output block size");
  527.     };
  528. };
  529.  
  530. /*
  531.  * HashAny is just a switching routine.  It calls the appropriate
  532.  * hash function
  533.  */
  534. void    HashAny (output, outputBlockSize, input, inputBlockSize, hashMethod)
  535.     word32 output[/* outputBlockSize */];
  536.     int outputBlockSize;
  537.     word32 input[/* inputBlockSize */];
  538.     int     inputBlockSize;
  539.     int     hashMethod;
  540. {
  541. #if DEBUG_SNEFRU
  542.     /* Yes, dimension testOutput with the max INPUT size --
  543.      * the input block size is guaranteed to be larger, and
  544.      * sometimes someone pushes the output size...
  545.      */
  546.     word32    testOutput[MAX_INPUT_BLOCK_SIZE];
  547.     int    i;
  548. #endif
  549.  
  550.     static int    flag = 0;
  551.  
  552.     switch ( hashMethod ) {
  553.         case MD4_METHOD:
  554.             Md4Block(output, outputBlockSize,
  555.                 input, inputBlockSize);
  556.             return;
  557.         case SNEFRU3_METHOD:
  558.         case SNEFRU4_METHOD:
  559.             switch (inputBlockSize) {
  560.             default: {
  561.                 if (flag == 0) {
  562.                     flag = 1;
  563.                     printf(
  564.         "Efficiency warning: using SnefruBlock (slow routine)\n");
  565.                 };
  566.                 SnefruBlock(output, outputBlockSize,
  567.                 input, inputBlockSize, hashMethod);
  568.                 return;
  569.                 };
  570.             case  1:
  571.             case  2:
  572.             case  3:
  573.             case  4:
  574.  
  575.                     Snefru128(output, outputBlockSize,
  576.                     input, inputBlockSize, hashMethod);
  577.                     break;
  578.             case  5:
  579.             case  6:
  580.             case  7:
  581.             case  8:
  582.  
  583.                     Snefru256(output, outputBlockSize,
  584.                     input, inputBlockSize, hashMethod);
  585.                     break;
  586.  
  587.             case   9:
  588.             case  10:
  589.             case  11:
  590.             case  12:
  591.  
  592.                     Snefru384(output, outputBlockSize,
  593.                     input, inputBlockSize, hashMethod);
  594.                     break;
  595.             case 13:
  596.             case 14:
  597.             case 15:
  598.             case 16:
  599.  
  600.                     Snefru512(output, outputBlockSize,
  601.                     input, inputBlockSize, hashMethod);
  602.                     break;
  603.                 };
  604. /* Testing code -- if you want to verify the faster implementations
  605.  * of Snefru put this code back in place.  It's painfully slow....
  606.  */
  607. #if DEBUG_SNEFRU
  608.     SnefruBlock(testOutput, outputBlockSize,
  609.         input, inputBlockSize, hashMethod);
  610.     for (i=0; i<outputBlockSize; i++)
  611.         if(testOutput[i] != output[i]) {
  612.             PrintIt("input =",input,   inputBlockSize);
  613.             PrintIt("output=",output, outputBlockSize);
  614.             PrintIt("testOutput=", testOutput, outputBlockSize);
  615.             ErrAbort("Bad Snefru hash");
  616.         };
  617. #endif
  618.             break;
  619.         default:
  620.             ErrAbort("Bad hash method specifier");
  621.         };
  622. }
  623.  
  624. /*  The following routine is a variant of HashAny which expects
  625.     to generate more output bits than input bits.  That is,
  626.     outputBlockSize is larger than inputBlockSize.  It is used
  627.     to expand a small amount of random information into a large
  628.     amount of pseudo-random information.
  629. */
  630. void    HashExpand (
  631.     outputBlock, outputBlockSize,
  632.     inputBlock, inputBlockSize,
  633.     hashMethod)
  634. word32 outputBlock[/* outputBlockSize */];
  635. int outputBlockSize;
  636. word32 inputBlock[/* inputBlockSize */];
  637. int     inputBlockSize;
  638. int     hashMethod;
  639. {
  640.     int i;
  641.     word32 tempBlock[MAX_INPUT_BLOCK_SIZE];
  642.     int tempOutputSize;
  643.     int tempInputSize;
  644.  
  645.     if (inputBlockSize >= MAX_INPUT_BLOCK_SIZE)
  646.         ErrAbort("inputBlockSize too large in HashExpand");
  647.     Copy (&tempBlock[1], inputBlock, inputBlockSize);
  648.     for (i=inputBlockSize+1; i<MAX_INPUT_BLOCK_SIZE; i++)
  649.         tempBlock[i]=0;
  650.     switch ( hashMethod ) {
  651.         case MD4_METHOD:
  652.             tempInputSize  = 16;
  653.             tempOutputSize = 4;
  654.             break;
  655.         case SNEFRU3_METHOD:
  656.         case SNEFRU4_METHOD:
  657.             tempInputSize  = MAX_INPUT_BLOCK_SIZE;
  658.             tempOutputSize = MAX_INPUT_BLOCK_SIZE-2;
  659.             break;
  660.         default:
  661.             ErrAbort("Bad hash method specifier");
  662.         };
  663.     if (inputBlockSize >= tempInputSize)
  664.                  ErrAbort("input to HashExpand too large");
  665.     for(i=0; i < outputBlockSize; i += tempOutputSize)  {
  666.         if (tempOutputSize > outputBlockSize-i)
  667.             tempOutputSize = outputBlockSize-i;
  668.         tempBlock[0]=i;
  669.         HashAny(&outputBlock[i], tempOutputSize,
  670.             tempBlock, tempInputSize, hashMethod);
  671.         };
  672. }
  673.  
  674.  
  675.  
  676. /*  internal diagnostics. Make sure the S-Boxes aren't
  677. messed up, that the one-way hash function is correct, etc. */
  678. void DoSelfTest(testingLevel)
  679.     int    testingLevel;
  680. {
  681.     int     i;
  682.  
  683.     if (testingLevel <= 0) return;
  684.     /* Test the standard S boxes to make sure they haven't been
  685.        damaged.  */
  686.     /* Test to make sure each column is a permutation.  */
  687.     for (i = 0; i < MAX_SBOX_COUNT; i++) {
  688.         char    testArray[256];
  689.         int     testShift = 0;
  690.         int     j;
  691.  
  692.         for (testShift = 0; testShift < 32; testShift += 8) {
  693.             for (j = 0; j < 256; j++)
  694.                 testArray[j] = 0;
  695.             for (j = 0; j < 256; j++)
  696.                 testArray[(standardSBoxes[i][j] >>
  697.                     testShift) & 0xff]++;
  698.             for (j = 0; j < 256; j++)
  699.                 if (testArray[j] != 1)
  700.                     ErrAbort
  701.             ("Table error -- the standard S box is corrupted");
  702.         };
  703.     };
  704.     /* Okay, the standard S-box hasn't been damaged  */
  705.  
  706.  
  707.  
  708.     /* Now try hashing something.  */
  709.     {
  710.         word32 testInput[MAX_INPUT_BLOCK_SIZE];
  711.         word32 testOutput[OUTPUT_BLOCK_SIZE];
  712.         int     j;
  713.         int    k;
  714.  
  715.  
  716.         if (OUTPUT_BLOCK_SIZE != 8)
  717.             ErrAbort ("The output block size has changed, update the self-test");
  718.         if (MAX_INPUT_BLOCK_SIZE != 16)
  719.             ErrAbort ("The input block size has changed, update the self-test");
  720.         if (MAX_SBOX_COUNT != 8)
  721.             ErrAbort ("Wrong number of S boxes, update the self-test");
  722.  
  723.         for (i = 0; i < MAX_INPUT_BLOCK_SIZE; i++)
  724.             testInput[i] = 0;    /* zero the input */
  725.         k = 0;  /*  zero the pointer into the input buffer */
  726.         for (i = 0; i < 50; i++) {
  727.             SnefruBlock (testOutput, 8, testInput,16, 4);
  728.             /*    Copy the output into a new slot in the input buffer */
  729.             for (j = 0; j < OUTPUT_BLOCK_SIZE; j++)
  730.                 testInput[k+j] = testOutput[j];
  731.             k += OUTPUT_BLOCK_SIZE;
  732.                 /*    reset pointer into input buffer
  733.                     if it might overflow next time */
  734.             if ( (k+OUTPUT_BLOCK_SIZE) > MAX_INPUT_BLOCK_SIZE) k=0;
  735.         };
  736.         if (    (testOutput[0] != 0x754D12FBL)    ||
  737.             (testOutput[1] != 0xA04197D2L)    ||
  738.             (testOutput[2] != 0xE92A9C7EL)    ||
  739.             (testOutput[3] != 0x4298FF88L)    ||
  740.             (testOutput[4] != 0xFCA820CFL)    ||
  741.             (testOutput[5] != 0x344FDDE6L)    ||
  742.             (testOutput[6] != 0x424DD3CAL)    ||
  743.             (testOutput[7] != 0x135EFF62L)  )
  744.             ErrAbort ("Test hash of 64 bytes of 0 failed");
  745.     };
  746.     /* Okay, we can hash at least 50  64-byte values correctly.  */
  747. }
  748.  
  749.  
  750. /*
  751.  * The following routine accepts, as input, a file name.
  752.  * The contents of the file are hashed, and the hash result
  753.  * is put into "hashValue".
  754.  */
  755. void
  756. SnefruHashFile (inputFile, hashValue, hashValueSize, securityLevel)
  757.     FILE    *inputFile;
  758.     word32    hashValue[];
  759.     int    hashValueSize;
  760.     int    securityLevel;
  761. {    int     i;
  762.     word32 hash[SNEFRU_INPUT_BLOCK_SIZE];
  763.     int    chunkSize;
  764.     word32 bitCount[2];    /* the 64-bit count of the number of
  765.                      * bits in the input */
  766.     long int byteCount;    /* the count of the number of bytes we just
  767.                  * read */
  768.  
  769.     if (hashValueSize >= SNEFRU_INPUT_BLOCK_SIZE)
  770.         ErrAbort("hashValueSize >= SNEFRU_INPUT_BLOCK_SIZE");
  771.     bitCount[0] = 0;
  772.     bitCount[1] = 0;
  773.     for (i = 0; i < SNEFRU_INPUT_BLOCK_SIZE; i++)
  774.         hash[i] = 0;    /* initialize hash  */
  775.     /*
  776.      * Hash each chunk in the input and keep the result in hash.
  777.      * Note that the first 16 (32) bytes of hash holds the output
  778.      * of the previous hash
  779.      * computation done during the previous iteration of the loop
  780.      */
  781.     chunkSize = SNEFRU_INPUT_BLOCK_SIZE - hashValueSize;
  782.     do {
  783.         /* Get the next chunk */
  784.         byteCount = ReadChunk (inputFile, &hash[hashValueSize],
  785.             chunkSize);
  786.         Increment64BitCounter (bitCount, 8*byteCount);
  787.         /* hash in the block we just read  */
  788.         if (byteCount > 0)
  789.             Snefru512 (hash, hashValueSize,
  790.                 hash, SNEFRU_INPUT_BLOCK_SIZE, securityLevel);
  791.     } while (byteCount > 0);  /* end of while */
  792.  
  793.     /*
  794.      * Put the 64-bit bit-count into the final 64-bits of the block about
  795.      * to be hashed
  796.      */
  797.     hash[SNEFRU_INPUT_BLOCK_SIZE - 2] = bitCount[0];/* upper 32 bits of
  798.                              * count */
  799.     hash[SNEFRU_INPUT_BLOCK_SIZE - 1] = bitCount[1];/* lower 32 bits of
  800.                              * count */
  801.     /* Final hash down.  */
  802.     Snefru512 (hashValue, hashValueSize,
  803.             hash, SNEFRU_INPUT_BLOCK_SIZE, securityLevel);
  804. }
  805.  
  806.